#include "Node.h"
#include <e32base.h>

#include "stringdef.h"
#include "HtmlBody.h"

#include "RenderObject.h"
#include "HtmlStyle.h"
//using namespace Renderer;

namespace DOM
{
Node::Node() : iFirstChild(0),
				iLastChild(0),
				iNextSibling(0),
				iPreSibling(0),
				iTagName(0),
				iChildNodeCount(0)
{
}

Node::~Node()
{
delete iTagName;
iTagName = NULL;
}

void Node::AppendChild(Node* aChild)
	{
	if(iFirstChild == NULL)
		{
		iFirstChild = iLastChild = aChild;
		aChild->setParentNode(this);
		iChildNodeCount++;
		
		if(NodeType() == Node::NTDocument)
			{
			if(aChild->NodeType() != Node::NTElement)
				return;
			else  //body
				{
				GetRenderObject()->AppendChildL(aChild->GetRenderObject());
				}
			}
		else
			{
			GetRenderObject()->AppendChildL(aChild->GetRenderObject());
			}
		}
	else
		{
		iLastChild->setNextSibling(aChild);
		aChild->setPreSibling(iLastChild);
		iLastChild = aChild;
		aChild->setParentNode(this);
		iChildNodeCount++;
		
		if(NodeType() == Node::NTDocument)
			{
			if(aChild->NodeType() != Node::NTElement)
				return;
			else  //body
				{
				//RenderView
				GetRenderObject()->AppendChildL(aChild->GetRenderObject());
				}
			}
		else
			{
			if(aChild->PreSibling() && 
			   aChild->PreSibling()->GetRenderObject()->GetHtmlStyle()->iDisplay == HtmlStyle::DisplayBlock)
				{
				//RenderObject在AppendChild时，需要自己判断是否要创建AnonymousBlock
				GetRenderObject()->AppendChildL(aChild->GetRenderObject());  
				}
			//前一个节点的父节点为AnonymousBlock
			else if(aChild->PreSibling() && 
			   aChild->PreSibling()->GetRenderObject()->GetHtmlStyle()->iDisplay == HtmlStyle::DisplayInline)
				{
				aChild->PreSibling()->GetParentNode()->GetRenderObject()->AppendChildL(aChild->GetRenderObject());
				
				}
			}
		}
	
	
	}

void Node::Attach(Renderer::RenderObject* aObj)
	{
	iRenderObject = aObj;
	
	if(!aObj->GetHtmlStyle()->IsSet(HtmlStyle::setDisplay))
		{
		if(GetDefaultFlowType() == Node::FTBlock)
			aObj->GetHtmlStyle()->iDisplay = HtmlStyle::DisplayBlock;
		else if(GetDefaultFlowType() == Node::FTInline)
			aObj->GetHtmlStyle()->iDisplay = HtmlStyle::DisplayInline;
		}
	
	
	}

Node* Node::CreateNodeL(const TDesC& aDes)
{
	HBufC* pBuf = HBufC::NewL(aDes.Length());
	CleanupStack::PushL(pBuf);
	TPtr ptr = pBuf->Des();
	ptr.Copy(aDes);
	ptr.TrimAll();
	ptr.LowerCase();
	
	Node* retNode = NULL;
	TInt findPos = -1;
	if((findPos = ptr.Find(KDOMStrBody)) != KErrNotFound)  //body
		retNode = new(ELeave) HtmlBody;
	else if((findPos = ptr.Find(KDOMStrDIV)) != KErrNotFound) //div
		retNode = new(ELeave) HtmlDiv;
	
	if(findPos != KErrNotFound && retNode)
		{
		if(findPos != 0)
			{
			if(ptr[findPos-1] == '/')
				retNode->SetTagType(TTEnd);
			else
				retNode->SetTagType(TTBegin);
			}
		else
			retNode->SetTagType(TTBegin);
			
		if(ptr[ptr.Length()-1] == '/')
			retNode->SetTagType(TTBoth);
		}
	
	//style
	if(retNode)
		{
		findPos = ptr.Find(KRenderStrStyle);
		if(findPos != KErrNotFound)
			{
			TPtrC ptrStyle = ptr.Mid(findPos+6);
			TBool isBegin = EFalse;
			TInt nFlag = -1;
			TInt nBeginQuotesPos = -1;
			TInt nEndQuotesPos = -2;
			TUint16* styleData = (TUint16*)ptrStyle.Ptr();
			for(TInt i = 0; i < ptrStyle.Length(); i++)
				{
				if(!isBegin)
					{
					if(styleData[i] == '"' || styleData[i] == '\'')
						{
						isBegin = ETrue;
						nBeginQuotesPos = i;
						if(styleData[i] == '"')
							nFlag = 1;
						else
							nFlag = 2;
						}
					
					}
				else if(isBegin && styleData[i] == '"' && nFlag == 1)
					{
					nEndQuotesPos = i;
					break;
					}
				else if(isBegin && styleData[i] == '\'' && nFlag == 2)
					{
					nEndQuotesPos = i;
					break;
					}
				}
			
			TPtrC ptrStyleData = ptrStyle.Mid(nBeginQuotesPos+1,nEndQuotesPos-nBeginQuotesPos-1);
			Renderer::RenderObject* ro = Renderer::RenderObject::CreateRenderObjectL(retNode,ptrStyleData);
			retNode->Attach(ro);

			}
		}
	
	CleanupStack::PopAndDestroy(1);
	
	return retNode;
}

void Node::TagName(TDes aBuf)
	{
	if(iTagName)
		aBuf.Copy(*iTagName);
	}

void Node::SetTagNameL(const TDesC& aTagName)
	{
	if(iTagName)
		{
		delete iTagName;
		iTagName= NULL;
		}
	
	iTagName = HBufC::NewL(aTagName.Length());
	CleanupStack::PushL(iTagName);
	TPtr ptr = iTagName->Des();
	ptr.Copy(aTagName);
	ptr.Trim();
	CleanupStack::Pop(1);
	}

}
